/* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include "modbus.h"
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <stdint.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include "cJSON.h"
#include "list.h"
#include "shmem.h"
#include "msg_queue_peer.h"
#define msgqueuename "msgqueue"
#define shmemname "shmem"

#define port 502
#define pointtablewhere "/mnt/config/pointtable.json"

typedef union {
    long l;
    float f;
} Converter;

struct mb_node
{
    int key;        //唯一键值
    char name[128]; //数据点名称
    int type;       //数据点类型
    int addr;
};

struct mb_node_list
{
    struct mb_node node;
    struct list_head list;
};

union val_t {

    int bool;
    int a;
    float b;
};
struct std_node //插入共享内存的数据
{
    int key;
    int type;
    int dev_type;
    union val_t old_val;
    union val_t new_val;
    int ret;
};
struct msgqueue //消息队列的结构
{
    int typekey;
    char data[64];
};
modbus_t *ctx;
struct list_head head;
void *pthread_read(void *arg);
void *pthread_write(void *arg);
void insertcorelist(cJSON *data, struct mb_node *p, int i, struct list_head *plist);
float stringToFloat(const char *str);
int main(int argc, char const *argv[])
{
    struct mb_node A, B, C, D, E;
    //初始化内核链表

    INIT_LIST_HEAD(&head);

    //打开cjson
    char cjson_buf[4096] = "";
    FILE *fp = fopen(pointtablewhere, "r");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    fread(cjson_buf, 4096, 1, fp);
    //printf("%s\n",cjson_buf);
    //获取root根节点
    cJSON *root = cJSON_Parse(cjson_buf);
    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    cJSON *add0 = cJSON_GetObjectItem(root, "mb_dev");
    cJSON *addr = cJSON_GetObjectItem(add0, "addr");
    cJSON *data = cJSON_GetObjectItem(modbus, "data");

    //从点表获取slave地址
    char addbuf[32] = ""; //slave地址
    strcpy(addbuf, addr->valuestring);

    //链表插入E
    insertcorelist(data, &E, 4, &head);
    //链表插入D
    insertcorelist(data, &D, 3, &head);
    //链表插入C
    insertcorelist(data, &C, 2, &head);
    //链表插入B
    insertcorelist(data, &B, 1, &head);
    //链表插入A
    insertcorelist(data, &A, 0, &head);
    //创建实例
    ctx = modbus_new_tcp(addbuf, port);

    //设置从机
    if (modbus_set_slave(ctx, 1) < 0)
    {
        perror("set slave err");
        return -1;
    }

    //建立链接
    if (modbus_connect(ctx) < 0)
    {
        perror("connect err");
        return -1;
    }
    printf("connect success\n");

    //创建从线程
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, pthread_read, NULL) != 0)
    {
        perror("tid1 pthread create err");
        return -1;
    }
    if (pthread_create(&tid2, NULL, pthread_write, NULL) != 0)
    {
        perror("tid2 pthread create err");
        return -1;
    }

    //回收线程
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    //关闭套接字
    modbus_close(ctx);

    //释放实例
    modbus_free(ctx);
    return 0;
}
//读取数据并写入共享内存
//slave端选择小端输出AB CD
void insertcorelist(cJSON *data, struct mb_node *p, int i, struct list_head *plist)
{
    //数据插入结构体
    cJSON *item = cJSON_GetArrayItem(data, i);
    cJSON *t = cJSON_GetObjectItem(item, "key");
    p->key = t->valueint;
    t = cJSON_GetObjectItem(item, "name");
    strcpy(p->name, t->valuestring);
    t = cJSON_GetObjectItem(item, "type");
    p->type = t->valueint;
    t = cJSON_GetObjectItem(item, "addr");
    p->addr = t->valueint;
    //链表插入a
    // 动态分配内存并将数据复制过去
    struct mb_node_list *node = malloc(sizeof(struct mb_node_list));
    if (node == NULL)
    {
        // 处理内存分配失败的情况
    }
    node->node = *p; // 将数据复制到动态分配的内存中

    list_add(&node->list, plist);
}
void *pthread_read(void *arg)
{
    printf("进入读线程\n");
    //打开共享内存
    struct shm_param shm;
    int *ptr = NULL;
    if (shm_init(&shm, shmemname, 1024) < 0)
    {
        printf("init err\n");
        return NULL;
    }

    ptr = shm_getaddr(&shm);
    if (ptr == NULL)
    {
        printf("shm_get err\n");
        return NULL;
    }

    //指针指向数据部分
    struct std_node *ptr_data = (struct std_node *)(ptr + 1);
    struct std_node *ptr_origin = ptr_data; //保存出发位置
    //ptr_data=ptr_origin;
    //读取并写入模块
    uint8_t buf[8];
    uint16_t regis[16];
    uint16_t regis_input[16];
    //开始循环读取数据，并写入共享内存
    while (1)
    {
        //读警报灯和车间門
        modbus_read_bits(ctx, 0, 2, buf);
        for (int i = 0; i < *ptr; i++)
        {
            if (ptr_data->key == 103) //报警灯
            {
                ptr_data->old_val.bool = ptr_data->new_val.bool;
                ptr_data->new_val.bool = buf[0];
                printf("报警灯状态是:%d\n", ptr_data->new_val.bool);
            }
            if (ptr_data->key == 105) //车间門
            {
                ptr_data->old_val.bool = ptr_data->new_val.bool;
                ptr_data->new_val.bool = buf[1];
                printf("车间門状态是:%d\n", ptr_data->new_val.bool);
            }
            ptr_data++;
        }
        ptr_data = ptr_origin;
        //读温度
        modbus_read_registers(ctx, 0, 2, regis);
        long data1 = (long)regis[0];
        long data2 = (long)regis[1];
        data1 = data1 << 16;
        data1 = data2 + data1;
        Converter converter;
        converter.l = data1;
        for (int i = 0; i < *ptr; i++)
        {
            if (ptr_data->key == 104) //温度为
            {
                ptr_data->old_val.b = ptr_data->new_val.b;
                ptr_data->new_val.b = converter.f;
                printf("温度是:%f\n", ptr_data->new_val.b);
            }
            ptr_data++;
        }
        ptr_data = ptr_origin;

        //读工厂人数和运转机器数量
        modbus_read_input_registers(ctx, 0, 2, regis_input);
        for (int i = 0; i < *ptr; i++)
        {
            if (ptr_data->key == 101) //工人数
            {
                ptr_data->old_val.a = ptr_data->new_val.a;
                ptr_data->new_val.a = regis_input[0];
                printf("当前工人数: %d\n", ptr_data->new_val.bool);
            }
            if (ptr_data->key == 102) //机器数
            {
                ptr_data->old_val.a = ptr_data->new_val.a;
                ptr_data->new_val.a = regis_input[1];
                printf("运转机器数:%d\n", ptr_data->new_val.bool);
            }
            ptr_data++;
        }
        ptr_data = ptr_origin;
        memset(buf, 0, 8);
        memset(regis, 0, 16);
        memset(regis_input, 0, 16);
        sleep(3);
    }

    return NULL;
}
float stringToFloat(const char *str)
{
    return strtof(str, NULL);
}
//写入数据的线程函数
void *pthread_write(void *arg)
{
    printf("进入写线程\n");
    struct msgqueue msg;
    while (1)
    {
        struct list_head *pos;
        struct mb_node_list *tmp;
        //接收温度控制消息
        if (msg_queue_recv(msgqueuename, &msg, sizeof(struct msgqueue), 104, IPC_NOWAIT) != -1)
        {
            float temper = stringToFloat(msg.data);

            //float->两个寄存器的usined char
            Converter send;
            send.f = temper;
            printf("上位机设置温度为%.1f\n", temper);
            uint16_t src[2];
            src[0] = (send.l >> 16) & 0xFFFF; // 高位数据
            src[1] = send.l & 0xFFFF;         // 低位数据

            //找到发送地址

            list_for_each(pos, &head)
            {
                tmp = list_entry(pos, struct mb_node_list, list);
                if (tmp->node.key == 104)
                {
                    int writeadd = (tmp->node.addr) - 40001;
                    modbus_write_registers(ctx, writeadd, 2, src);
                }
            }
        }

        //接收报警灯控制消息
        if (msg_queue_recv(msgqueuename, &msg, sizeof(struct msgqueue), 103, IPC_NOWAIT) != -1)
        //字符转化成数字
        {
            uint8_t status_wlight = *(msg.data) - 48;
            printf("上位机设置报警灯为%d\n", status_wlight);
            list_for_each(pos, &head)
            {
                tmp = list_entry(pos, struct mb_node_list, list);
                if (tmp->node.key == 103)
                {
                    int writeadd = (tmp->node.addr) - 1;
                    modbus_write_bit(ctx, writeadd, status_wlight);
                }
            }
        }

        
        //接收车间門控制消息
       if(msg_queue_recv(msgqueuename, &msg, sizeof(struct msgqueue), 105, IPC_NOWAIT)!=-1) 
       {
            //字符转化成数字
        uint8_t status_wsdoor = *(msg.data) - 48;
        printf("上位机设置报警灯为%d\n", status_wsdoor);
        list_for_each(pos, &head)
        {
            tmp = list_entry(pos, struct mb_node_list, list);
            if (tmp->node.key == 105)
            {
                int writeadd = (tmp->node.addr) - 1;
                modbus_write_bit(ctx, writeadd, status_wsdoor);
            }
        }
       }
       
    }
}